﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using DevExpress.Web.ASPxCallback;
using TireService.Data;
using System.Configuration;
using System.IO;
using System.Web.Security;

namespace TireService.Web.View.AdminView
{
    public partial class CreateSubscriptionInvoice : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Page.IsPostBack != true)
            {
                // Show default start and end of present month
                txtStartdate.Value = "01-" + DateTime.Now.Month.ToString() + "-" + DateTime.Now.Year.ToString();
                txtEnddate.Value = Convert.ToDateTime("01-" + DateTime.Now.Month.ToString() + "-" + DateTime.Now.Year.ToString()).AddMonths(1).AddDays(-1).Day.ToString() + "-" + DateTime.Now.Month.ToString() + "-" + DateTime.Now.Year.ToString();
            }

            if (Convert.ToInt32(ddlMethod.SelectedItem.Value) != 0)
            {
                TireServiceDB db = new TireServiceDB();

                ShowSubscriptionsReadyForInvoicing(Convert.ToInt32(ddlMethod.SelectedItem.Value), Convert.ToDateTime(txtStartdate.Value), Convert.ToDateTime(txtEnddate.Value));
            }
        }

        /// <summary>
        /// Function that shows subscriptions that should be renewed with specified timeperiod
        /// </summary>
        /// <param name="Method">Renewal method</param>
        /// <param name="Startdate">Startdate of period</param>
        /// <param name="Enddate">Enddate of period</param>
        private void ShowSubscriptionsReadyForInvoicing(int Method, DateTime Startdate, DateTime Enddate)
        {
            TireServiceDB db = new TireServiceDB();

            // Get all subscriptions that should be renewed - (Criteria: Dateperiod has ended)
            var subscriptions = from p in db.CustomerSubscriptions
                                join v in db.Customers on p.CustomerId equals v.CustomerId into pv
                                from x in pv.DefaultIfEmpty()
                                join y in db.Cars on p.CustomerSubscriptionId equals y.CustomerSubscriptionId into py
                                from z in py.DefaultIfEmpty()
                                join w in db.Subscriptions on p.SubscriptionId equals w.SubscriptionId into pw
                                from q in pw.DefaultIfEmpty()
                                where p.InActive == false & (p.NextRenewalDate > Startdate & p.NextRenewalDate < Enddate) & z.CarId != null
                                orderby p.CustomerSubscriptionId descending
                                select new
                                {
                                    p.SubscriptionId,
                                    SubscriptionDescription = q.Description,
                                    p.CustomerSubscriptionId,
                                    p.LastRenewalDate,
                                    p.NextRenewalDate,
                                    p.Price,
                                    x.CustomerId,
                                    x.CompanyName,
                                    x.Name,
                                    x.Email,
                                    x.IsCompany,
                                    x.ParentPayInvoice,
                                    x.ParentCustomerId,
                                    x.InvoicePBS,
                                    x.ManualInvoicing,
                                    z.CarId,
                                    z.RegistrationNumber,
                                    q.ServiceDrivesIncluded
                                };

            if (Method == 1)
            {
                // Renew customers running on PBS
                gvSubscriptionInvoice.DataSource = subscriptions.Where(p => p.InvoicePBS == true).ToList();
            }

            if (Method == 2)
            {
                // Renew customers where invoice is send via e-mail
                gvSubscriptionInvoice.DataSource = subscriptions.Where(p => p.InvoicePBS == false & p.ManualInvoicing == false).ToList();
            }

            if (Method == 3)
            {
                // Renew customers that is manually invoiced
                gvSubscriptionInvoice.DataSource = subscriptions.Where(p => p.ManualInvoicing == true).ToList();
            }

            gvSubscriptionInvoice.DataBind();

            db.Dispose();
        }

        /// <summary>
        /// Function that renew subscriptions with a specific timeperiod
        /// </summary>
        /// <param name="Method">Method for renewing</param>
        /// <param name="Startdate">Startdate of period</param>
        /// <param name="Enddate">Enddate of period</param>
        private void RenewSubscriptions(int Method, DateTime Startdate, DateTime Enddate)
        { 
            TireServiceDB db = new TireServiceDB();

            // Array for subscription renewal log (1: CustomerSubscriptionId, 2: Action and description (Invoiced, Failed))
            Dictionary<int, string> renewal_log = new Dictionary<int, string>(); 
            
            // List of all subscriptions (system subscriptions)
            List<Subscription> subscriptions = db.GetSubscription();

            // Get list of customer subscriptions
            List<CustomerSubscription> customersubscriptions = db.GetCustomerSubscriptionsForRenewal(Startdate, Enddate);

            // Initiate E-conomic interface
            EconomicInterface ecoInterface = new EconomicInterface();

            // Initiate customersubscription log
            CustomerSubscriptionLogBLL customersubscriptionlogBLL = new CustomerSubscriptionLogBLL();

            // Initiate email service
            EmailNotificationServices emailService = new EmailNotificationServices();

            // Get user
            MembershipUser user = Membership.GetUser();

            // Run through each subscription
            int i = 0;
            //foreach (CustomerSubscription customersubscription in customersubscriptions.Take(Convert.ToInt32(ddlInvoiceCount.SelectedItem.Value)))
            foreach (CustomerSubscription customersubscription in customersubscriptions)
            {
                if (i < Convert.ToInt32(ddlInvoiceCount.SelectedItem.Value))
                {
                    // Get customer
                    Customer customer = db.GetCustomer(customersubscription.CustomerId);

                    if (Method == 1)
                    {
                        // PBS customers
                        if (customer.InvoicePBS)
                        {
                            RenewSubsubscription(db, renewal_log, subscriptions, ecoInterface, customersubscriptionlogBLL, emailService, user, customersubscription, customer, true, Method);
                            i += 1;
                        }
                    }

                    if (Method == 2)
                    {
                        // Email invoice
                        if (customer.InvoicePBS == false & customer.ManualInvoicing == false)
                        {
                            RenewSubsubscription(db, renewal_log, subscriptions, ecoInterface, customersubscriptionlogBLL, emailService, user, customersubscription, customer, true, Method);
                            i += 1;
                        }
                    }

                    if (Method == 3)
                    {
                        // Manual
                        if (customer.ManualInvoicing)
                        {
                            RenewSubsubscription(db, renewal_log, subscriptions, ecoInterface, customersubscriptionlogBLL, emailService, user, customersubscription, customer, false, Method);
                            i += 1;
                        }
                    }
                }
                else
	            {
                    // Nothing - count has been reached
	            }   
            }

            // Submit changes to database
            db.SubmitChanges();

            // Return log on renewal to finance email
            string logHTML = "<b>Faktura oversigt</b><br><table><tr><td>Abonnementnr</td><td>Status og handling</td></tr>";
            foreach (KeyValuePair<int, string> log in renewal_log)
            {
                logHTML += "<tr><td>" + log.Key.ToString() + "</td><td>" + log.Value + "</td></tr>";
            }
            logHTML += "</table>";

            string Subject = "Fornyet og faktureret abonnementer";
            emailService.SendFinanceInternalEmailNotification(Subject, logHTML);


            // Close connection to database
            db.Dispose();
        }

        /// <summary>
        /// Function that renew subscription and create invoice
        /// </summary>
        /// <param name="db">Connection to database</param>
        /// <param name="renewal_log">Log file on result</param>
        /// <param name="subscriptions">List of systems subscriptions</param>
        /// <param name="ecoInterface">Interface to E-conomic</param>
        /// <param name="customersubscription">Customer subscription to be renewed</param>
        /// <param name="customer">Customer that owns the subscription</param>
        /// <param name="BookInvoice">True/false value indicating if invoice should be booked (false means it will be a </param>
        /// <param name="RenewalMethod"></param>
        private void RenewSubsubscription(TireServiceDB db, Dictionary<int, string> renewal_log, List<Subscription> subscriptions, EconomicInterface ecoInterface, CustomerSubscriptionLogBLL customersubscriptionlogBLL, EmailNotificationServices emailService, MembershipUser user, CustomerSubscription customersubscription, Customer customer, bool BookInvoice, int RenewalMethod)
        {
            // Get cars
            List<Car> cars = db.GetCarByCustomerSubscriptionId(customersubscription.CustomerSubscriptionId);

            if (cars.Count > 1 | cars.Count == 0)
            {
                // Log failed renewal
                if (cars.Count > 1) renewal_log.Add(customersubscription.CustomerSubscriptionId, "Fejl: Sølv abonnement eller flere biler på et abonnement");
                if (cars.Count == 0) renewal_log.Add(customersubscription.CustomerSubscriptionId, "Fejl: Ingen bil tilknyttet til aktivt abonnement");
            }
            else
            {
                Car car = cars.First();

                if (car.CarStatusId == (int)Shared.CarStatus.InActive)
                {
                    // Log failed renewal
                    renewal_log.Add(customersubscription.CustomerSubscriptionId, "Fejl: Bil på abonnement står som inaktiv - abonnement kan ikke fornyes");
                }
                else
                {
                    int month = subscriptions.SingleOrDefault(p => p.SubscriptionId == customersubscription.SubscriptionId).SubscriptionLengthMonth;

                    // Create subscription log
                    customersubscriptionlogBLL.CreateCustomerSubscriptionLog(db, customersubscription, (int)Shared.SubscriptionLogAction.Renewal, new Guid(user.ProviderUserKey.ToString()), "Tidligere periode: " + customersubscription.LastRenewalDate.ToShortDateString() + " - " + customersubscription.NextRenewalDate.ToShortDateString());

                    // Renew subscription
                    customersubscription.LastRenewalDate = customersubscription.NextRenewalDate;
                    customersubscription.NextRenewalDate = customersubscription.LastRenewalDate.AddMonths(month);

                    // Get Customer Id on invoice payment responsible
                    CustomerBLL customerBLL = new CustomerBLL();
                    int PayingCustomerId = customerBLL.GetPayingCustomerId(db, customer.CustomerId);

                    // Check if any discount should be deducted in invoice amount
                    // TODO: Check in Quotation table if customer has refered new customers and earned discount

                    // Create invoice
                    // TODO: Check customer exists in E-conomic
                    string invoiceid = ecoInterface.CreateSubscriptionRenewalInvoice(db, PayingCustomerId, subscriptions.SingleOrDefault(p => p.SubscriptionId == customersubscription.SubscriptionId), customersubscription, car, BookInvoice);

                    if (RenewalMethod == (int)Shared.SubscriptionRenewalMethod.InvoicePBS)
                    {
                        renewal_log.Add(customersubscription.CustomerSubscriptionId, "OK: Faktura oprettet til PBS betaling - refnr: " + invoiceid);
                    }

                    if (RenewalMethod == (int)Shared.SubscriptionRenewalMethod.InvoiceEmail)
                    {
                        renewal_log.Add(customersubscription.CustomerSubscriptionId, "OK: Faktura oprettet og sendt pr. email - refnr: " + invoiceid);

                        Customer payingcustomer = db.GetCustomer(PayingCustomerId);

                        // Create function that emails invoice to customer
                        emailService.SubscriptionRenewal_SendCustomerInvoice(PayingCustomerId, payingcustomer.Email, payingcustomer.Name, customersubscription.CustomerId.ToString() + "-" + customersubscription.SubscriptionId.ToString() + "-" + customersubscription.CustomerSubscriptionId.ToString(), invoiceid, ecoInterface.GetInvoice(Convert.ToInt32(invoiceid)), "Faktura" + invoiceid + ".pdf", Convert.ToInt32(Shared.PaymentGateWayActions.InitiatePayment).ToString(), Convert.ToString(ConfigurationManager.AppSettings["AcceptURL"]));
                    }

                    if (RenewalMethod == (int)Shared.SubscriptionRenewalMethod.InvoiceManual)
                    {
                        renewal_log.Add(customersubscription.CustomerSubscriptionId, "OK: Faktura kladde oprettet - refnr: " + invoiceid + " (email: " + customer.Email + ")");    
                    }
                }
            }
        }

        /// <summary>
        /// Callback function that handles renewal of subscriptions and generation of invoices
        /// </summary>
        protected void callGenerateInvoices_Callback(object sender, CallbackEventArgs e)
        {
            // Get values (0: Method, 1: Startdate, 2: Enddate)
            string[] param = e.Parameter.Split('|');

            int Method = Convert.ToInt32(param[0]);
            DateTime Startdate = Convert.ToDateTime(param[1]);
            DateTime Enddate = Convert.ToDateTime(param[2]);

            RenewSubscriptions(Method, Startdate, Enddate);
        }

        /// <summary>
        /// Postback function that 
        /// </summary>
        protected void gvSubscriptionInvoice_CustomCallback(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewCustomCallbackEventArgs e)
        {
            // Get values (0: Method, 1: Startdate, 2: Enddate)
            string[] param = e.Parameters.Split('|');

            int Method = Convert.ToInt32(param[0]);
            DateTime Startdate = Convert.ToDateTime(param[1]);
            DateTime Enddate = Convert.ToDateTime(param[2]);

            ShowSubscriptionsReadyForInvoicing(Method, Startdate, Enddate);
        }
    }
}